%{
    #include "TreeNode.h"
	#include "lex.yy.c"	//directly copy to syntax.tab.c  
%}

%union {
    int type_int;              // Constant integer value 
    float type_float;              // Constant floating point value 
    char *type_str;              // Ptr to constant string 
    TreeNode * type_node;
}

%token <type_node> INT FLOAT ID SEMI COMMA ASSIGNOP RELOP PLUS MINUS STAR DIV AND OR DOT NOT TYPE LP RP LB RB LC RC STRUCT RETURN IF ELSE WHILE

%right ASSIGNOP
%left OR
%left AND
%left RELOP
%left  PLUS MINUS
%left STAR DIV
%right NOT
%left DOT LB RB LP RP

%nonassoc IF ELSE STRUCT RETURN WHILE

%type <type_node> Program ExtDefList ExtDef ExtDecList Specifier
%type <type_node> StructSpecifier OptTag Tag VarDec FunDec VarList
%type <type_node> ParamDec CompSt StmtList Stmt DefList Def DecList
%type <type_node> Dec Exp Args

%%

/*=========================High-level Definitions===========================*/


Program : ExtDefList {$$ = createNode("Program","\0");insertDescendent($$,$1);root = $$;}
    ;
ExtDefList : ExtDef ExtDefList {$$ = createNode("ExtDefList","\0");insertDescendent($$,$2);insertDescendent($$,$1);}
    |   {$$ = NULL;}
    ;
ExtDef : Specifier ExtDecList SEMI { $$ = createNode("ExtDef","\0");insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    |   Specifier SEMI {$$ = createNode("ExtDef","\0");insertDescendent($$,$2);insertDescendent($$,$1);}
    |   Specifier FunDec CompSt {$$ = createNode("ExtDef","\0");insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    |   Specifier FunDec SEMI {$$ = createNode("ExtDef","\0");insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    |   error SEMI {syntax_error++;printf("Error type B at Line %d: syntax error.\n",yylineno);}
    |   Specifier error SEMI {syntax_error++;printf("Error type B at Line %d: syntax error.\n",yylineno);}
    |   Specifier error {syntax_error++;printf("Error type B at Line %d: syntax error.\n",yylineno);}
    |   Specifier ExtDecList error {syntax_error++;printf("Error type B at Line %d: syntax error.\n",yylineno);}
    ;
ExtDecList : VarDec {$$ = createNode("ExtDecList","\0");insertDescendent($$,$1);}
    |   VarDec  COMMA   ExtDecList { $$ = createNode("ExtDecList","\0");insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    |   error COMMA ExtDecList {syntax_error++;printf("Error type B at Line %d: syntax error.\n",yylineno);}
    |   VarDec COMMA error {syntax_error++;printf("Error type B at Line %d: syntax error.\n",yylineno);}
    ;

/*=========================Specifier========================*/
Specifier : TYPE {$$ = createNode("Specifier","\0");insertDescendent($$,$1);}
    |   StructSpecifier {$$ = createNode("Specifier","\0");insertDescendent($$,$1);}
    ;
StructSpecifier : STRUCT OptTag LC DefList RC { $$  = createNode("StructSpecifier","\0");insertDescendent($$,$5);insertDescendent($$,$4);insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    |   STRUCT Tag { $$ = createNode("StructSpecifier","\0");insertDescendent($$,$2);insertDescendent($$,$1);}
    ;
OptTag : ID {$$=createNode("OptTag","\0");insertDescendent($$,$1);}
    |   /*empty*/ {$$=NULL;}
    ;
Tag : ID {$$=createNode("Tag","\0");insertDescendent($$,$1);}
    ;

/*======================Declarators======================*/
VarDec : ID {$$=createNode("VarDec","\0");insertDescendent($$,$1);}
    |   VarDec LB INT RB {$$=createNode("VarDec","\0");insertDescendent($$,$4);insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    ;
FunDec : ID LP VarList RP {$$=createNode("FunDec","\0");insertDescendent($$,$4);insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    |   ID LP RP {$$=createNode("FunDec","\0");insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    ;
VarList : ParamDec COMMA VarList {$$=createNode("VarList","\0");insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    | ParamDec {$$=createNode("VarList","\0");insertDescendent($$,$1);}
    ;
ParamDec : Specifier VarDec {$$=createNode("ParamDec","\0");insertDescendent($$,$2);insertDescendent($$,$1);} 
    ;


/*========================Statements=====================*/
CompSt : LC DefList StmtList RC {$$=createNode("CompSt","\0");insertDescendent($$,$4);insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    ;
StmtList : Stmt StmtList {$$ = createNode("StmtList","\0");insertDescendent($$,$2);insertDescendent($$,$1);}
    | /*empty*/ {$$ = NULL;}
    ;
Stmt : Exp SEMI {$$=createNode("Stmt","\0");insertDescendent($$,$2);insertDescendent($$,$1);}
    | CompSt {$$=createNode("Stmt","\0");insertDescendent($$,$1);}
    | RETURN Exp SEMI {$$=createNode("Stmt","\0");insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    | RETURN SEMI {$$=createNode("Stmt","\0");insertDescendent($$,$2);insertDescendent($$,$1);}
    | IF LP Exp RP Stmt {$$=createNode("Stmt","\0");insertDescendent($$,$5);insertDescendent($$,$4);insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    | IF LP Exp RP Stmt ELSE Stmt {$$=createNode("Stmt","\0");insertDescendent($$,$7);insertDescendent($$,$6);insertDescendent($$,$5);insertDescendent($$,$4);insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    | WHILE LP Exp RP Stmt {$$=createNode("Stmt","\0");insertDescendent($$,$5);insertDescendent($$,$4);insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    | Exp error SEMI {syntax_error++;printf("Error type B at Line %d: Missing \";\".\n",yylineno);}
    | error SEMI {syntax_error++;printf("Error type B at Line %d: syntax error.\n",yylineno);}
    ;

/*-------------------------Local Definitions----------------------*/
DefList : Def DefList {$$=createNode("DefList","\0");insertDescendent($$,$2);insertDescendent($$,$1);}
    | {$$=NULL;}
    ;
Def : Specifier DecList SEMI {$$=createNode("Def","\0");insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    ;
DecList : Dec {$$=createNode("DecList","\0");insertDescendent($$,$1);}
    | Dec COMMA DecList {$$=createNode("DecList","\0");insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    ;
Dec : VarDec {$$=createNode("Dec","\0");insertDescendent($$,$1);}
    | VarDec ASSIGNOP Exp {$$=createNode("VarDec","\0");insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    ;

/*---------------------Expressions------------------------*/
Exp : Exp ASSIGNOP Exp {$$=createNode("Exp","\0");insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    | Exp AND Exp {$$=createNode("Exp","\0");insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    | Exp OR Exp {$$=createNode("Exp","\0");insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    | Exp RELOP Exp {$$=createNode("Exp","\0");insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    | Exp PLUS Exp {$$=createNode("Exp","\0");insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    | Exp MINUS Exp {$$=createNode("Exp","\0");insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    | Exp STAR Exp {$$=createNode("Exp","\0");insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    | Exp DIV Exp {$$=createNode("Exp","\0");insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    | LP Exp RP {$$=createNode("Exp","\0");insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    | MINUS Exp {$$=createNode("Exp","\0");insertDescendent($$,$2);insertDescendent($$,$1);}
    | NOT Exp {$$=createNode("Exp","\0");insertDescendent($$,$2);insertDescendent($$,$1);}
    | ID LP Args RP {$$=createNode("Exp","\0");insertDescendent($$,$4);insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    | ID LP RP {$$=createNode("Exp","\0");insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    | Exp LB Exp RB {$$=createNode("Exp","\0");insertDescendent($$,$4);insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    | Exp DOT ID {$$=createNode("Exp","\0");insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    | ID {$$=createNode("Exp","\0");insertDescendent($$,$1);}
    | INT {$$=createNode("Exp","\0");insertDescendent($$,$1);}
    | FLOAT {$$=createNode("Exp","\0");insertDescendent($$,$1);}
    | Exp LB error SEMI {syntax_error++;printf("Error type B at Line %d: Missing \"]\".\n",yylineno);}
    ;
Args : Exp COMMA Args {$$=createNode("Args","\0");insertDescendent($$,$3);insertDescendent($$,$2);insertDescendent($$,$1);}
    | Exp {$$=createNode("Args","\0");insertDescendent($$,$1);}
    ;

%%


int yyerror(char* msg){
    //printf("some error detected!");
    //NO action cus error has been reported in the above
}

